package com.zhuang.jdk8.streamapi;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import com.zhuang.jdk8.methodreference.Person;

public class DemoSteam {
	public static void main(String[] args) {
		//streamreduce();
		//streammaptoint();
		testStreamFilter();
	}

	public static void streamfor() {
		List<String> list = new ArrayList<String>();
		list.add("张无忌");
		list.add("周芷若");
		list.add("赵敏");
		list.add("张强");
		list.add("张三丰");
// 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义：获取流、过滤姓张、过滤长度为3、逐一打印。我们真 正要做的事情内容被更好地体现在代码中。
		list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);

		List<String> one = new ArrayList<>();
		// forEach 用来遍历流中的数据
		Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
		one.stream().forEach(t -> {
			System.out.println(t);
		});
		one.stream().forEach(s -> System.out.println(s));
		System.out.println("---------------");
		one.stream().forEach(System.out::println);

	}

	public static void streamapi() {
		List<String> one = new ArrayList<>();
		// forEach 用来遍历流中的数据
		Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
		one.stream().forEach(System.out::println);
		// Stream流提供 count 方法来统计其中的元素个数：
		System.err.println(one.stream().count());
		// 通过 filter 方法将一个流转换成另一个子集流
		one.stream().filter(s -> s.length() == 2).forEach(System.out::println);
		// limit 方法可以对流进行截取，只取用前n个。
		one.stream().limit(3).forEach(System.out::println);
		// 如果希望跳过前几个元素，可以使用 skip 方法获取一个截取之后的新流：
		one.stream().skip(2).forEach(System.out::println);

		// 如果需要将流中的元素映射到另一个流中，可以使用 map 方法
		Stream<String> original = Stream.of("11", "22", "33");
		Stream<Integer> result = original.map(Integer::parseInt);
		result.forEach(s -> System.out.println(s + 10));
		System.out.println("---------------");
		// sorted(): 根据元素的自然顺序排序
		// sorted(Comparator<? super T> comparator): 根据比较器指定的规则排序
		Stream.of(33, 22, 11, 55).sorted().sorted((o1, o2) -> o1 - o2).forEach(System.out::println);
		// 如果需要去除重复数据，可以使用 distinct方法
		Stream.of(22, 33, 22, 11, 33).distinct().forEach(System.out::println);
		System.out.println("---------------");
		// 如果需要找到某些数据，可以使用 find 相关方法
		Optional<Integer> first = Stream.of(5, 3, 6, 1).findFirst();
		System.out.println("first = " + first.get());
		Optional<Integer> any = Stream.of(8, 3, 6, 1).findAny();
		System.out.println("any = " + any.get());
		System.out.println("---------------");
		// 如果需要获取最大和最小值，可以使用 max 和 min 方法
		Optional<Integer> max = Stream.of(5, 3, 6, 1).max((o1, o2) -> o1 - o2);
		System.out.println("first = " + max.get());
		Optional<Integer> min = Stream.of(5, 3, 6, 1).min((o1, o2) -> o1 - o2);
		System.out.println("any = " + min.get());
	}

	public static void streamreduce() {
		int reduce = Stream.of(4, 5, 3, 9).reduce(0, (a, b) -> {
			System.out.println("a = " + a + ", b = " + b);
			return a + b;
		});
		// reduce:
		// 第一次将默认做赋值给x, 取出第一个元素赋值给y,进行操作
		// 第二次,将第一次的结果赋值给x, 取出二个元素赋值给y,进行操作
		// 第三次,将第二次的结果赋值给x, 取出三个元素赋值给y,进行操作
		// 第四次,将第三次的结果赋值给x, 取出四个元素赋值给y,进行操作
		System.out.println("reduce = " + reduce);
		int reduce2 = Stream.of(4, 5, 3, 9).reduce(0, Integer::sum);
		System.out.println("reduce2 = " + reduce2);
		int reduce3 = Stream.of(4, 5, 3, 9).reduce(0, Integer::sum);
		System.out.println("reduce3 = " + reduce3);
		int max = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> x > y ? x : y);

		System.out.println("max = " + max);
		System.out.println("---------------------------------");
		// 求出所有年龄的总和
		int totalAge = Stream
				.of(new Person("刘德华", 58), new Person("张学友", 56), new Person("郭富城", 54), new Person("黎明", 52))
				.map(Person::getAge).reduce(0, Integer::sum);
		System.out.println("totalAge = " + totalAge);
		// 找出最大年龄
		int maxAge = Stream
				.of(new Person("刘德华", 58), new Person("张学友", 56), new Person("郭富城", 54), new Person("黎明", 52))
				.map(Person::getAge).reduce(0, (x, y) -> x > y ? x : y);
		System.out.println("maxAge = " + maxAge);
		// 统计 数字2 出现的次数
		int count = Stream.of(1, 2, 2, 1, 3, 2).map(i -> {
			if (i == 2) {
				return 1;
			} else {
				return 0;
			}
		}).reduce(0, Integer::sum);
		System.out.println("count = " + count);
		System.out.println("---------------------------------");
	}

	public static void streammaptoint() {
		// Integer占用的内存比int多,在Stream流操作中会自动装箱和拆箱
		Stream<Integer> stream = Arrays.stream(new Integer[] { 1, 2, 3, 4, 5 });
		// 把大于3的和打印出来

		// Integer result = stream.filter(i -> i.intValue() > 3).reduce(0,
		// Integer::sum);
		// System.out.println(result);

		// 先将流中的Integer数据转成int,后续都是操作int类型
		IntStream intStream = stream.mapToInt(Integer::intValue);
		int reduce = intStream.filter(i -> i > 3).reduce(0, Integer::sum);
		System.out.println(reduce);
		// 将IntStream转化为Stream<Integer>
		IntStream intStream1 = IntStream.rangeClosed(1, 10);
		Stream<Integer> boxed = intStream1.boxed();
		boxed.forEach(s -> System.out.println(s.getClass() + ", " + s));

		Stream<String> streamA = Stream.of("张三");
		Stream<String> streamB = Stream.of("李四");
		Stream<String> result = Stream.concat(streamA, streamB);
		result.forEach(System.out::println);
	}

	public static void testStreamFilter(){
		List<String> list = Arrays.asList("jack", "tom", "penny");
		List<String> res = list.stream().filter(s -> s.equals("jack"))
				.map(s -> s = "raj").collect(Collectors.toList());
		res.forEach(System.out::println);
	}
}
